// Copyright 2011-2012, Vanya Davidenko.
// Используемая кодировка: UTF-8.

#ifndef LIBV_TESTS_BOOST_ITERATOR_ITERATOR_TESTS_H_
#define LIBV_TESTS_BOOST_ITERATOR_ITERATOR_TESTS_H_

#include <algorithm>
#include <deque>
#include <list>
#include <boost/assign.hpp>
#include <gtest/gtest.h>
#include <libv/boost/iterator_iterator.h>


namespace libv {
namespace tests {

class IteratorIteratorTests : public ::testing::Test {
  public:
    virtual void SetUp() {}
    virtual void TearDown() {}

  protected:
    typedef ::std::deque< ::std::list<int> > RangesContainer;
    typedef IteratorIterator<RangesContainer::const_iterator>
        MyIteratorIterator;

    ::std::deque<int> ToArray() const {
        return ::std::deque<int>(Begin(), End());
    }

    MyIteratorIterator Begin() const {
        if ( ranges_container_.empty() ) {
            return End();
        }
        return MyIteratorIterator(ranges_container_.begin(),
                                  ranges_container_.end());
    }

    MyIteratorIterator End() const {
        return MyIteratorIterator(ranges_container_.end(),
                                  ranges_container_.end());
    }


    template<class TRange1, class TRange2>
    bool AreEqual(const TRange1& r1, const TRange2& r2) const {
        if ( r1.empty() || r2.empty() ) {
            return r1.empty() == r2.empty();
        }
        return ::std::equal(r1.begin(), r1.end(), r2.begin()) &&
               ::std::equal(r2.begin(), r2.end(), r1.begin());
    }

    RangesContainer ranges_container_;
    ::std::list<int> empty_list_;
};



TEST_F(IteratorIteratorTests, Empty) {
    const ::std::deque<int> exp;
    ASSERT_TRUE(AreEqual(ToArray(), exp));
}

TEST_F(IteratorIteratorTests, DefaultConstructedEnd) {
    using namespace boost::assign;

    push_back(ranges_container_)(list_of(1));

    ::std::deque<int> exp = list_of(1).to_container(exp);
    EXPECT_TRUE(::std::equal(Begin(), MyIteratorIterator(), exp.begin()));
}


TEST_F(IteratorIteratorTests, FirstEmpty) {
    using namespace boost::assign;

    push_back(ranges_container_)(empty_list_)
                                (list_of(1)(2))
                                (list_of(3));

    const ::std::deque<int> exp = list_of(1)(2)(3).to_container(exp);
    ASSERT_TRUE(AreEqual(ToArray(), exp));
}

TEST_F(IteratorIteratorTests, MiddleEmpty) {
    using namespace boost::assign;

    push_back(ranges_container_)(list_of(1))
                                (empty_list_)
                                (list_of(2));

    const ::std::deque<int> exp = list_of(1)(2).to_container(exp);
    ASSERT_TRUE(AreEqual(ToArray(), exp));
}

TEST_F(IteratorIteratorTests, AllEmpty) {
    using namespace boost::assign;

    push_back(ranges_container_)(empty_list_)
                                (empty_list_)
                                (empty_list_);

    const ::std::deque<int> exp;
    ASSERT_TRUE(AreEqual(ToArray(), exp));
}


TEST_F(IteratorIteratorTests, Simple) {
    using namespace boost::assign;

    push_back(ranges_container_)(list_of(1))
                                (list_of(2))
                                (list_of(3));

    const ::std::deque<int> exp = list_of(1)(2)(3).to_container(exp);
    ASSERT_TRUE(AreEqual(ToArray(), exp));
}

TEST_F(IteratorIteratorTests, Lacerated) {
    using namespace boost::assign;

    push_back(ranges_container_)(list_of(1))
                                (list_of(2)(3))
                                (list_of(4));

    const ::std::deque<int> exp = list_of(1)(2)(3)(4).to_container(exp);
    ASSERT_TRUE(AreEqual(ToArray(), exp));
}


TEST_F(IteratorIteratorTests, EndIteratorEquality) {
    using namespace boost::assign;

    EXPECT_TRUE(MyIteratorIterator() == MyIteratorIterator());
    EXPECT_TRUE(MyIteratorIterator() == End());
    EXPECT_TRUE(MyIteratorIterator() == Begin());

    push_back(ranges_container_)(list_of(1));
    EXPECT_TRUE(++Begin() == End());
}

TEST_F(IteratorIteratorTests, IteratorEquality) {
    using namespace boost::assign;

    push_back(ranges_container_)(list_of(1))
                                (list_of(2)(3))
                                (list_of(4));

    MyIteratorIterator i = Begin();
    MyIteratorIterator i2 = Begin();
    EXPECT_TRUE(i == i2);

    ++i;
    EXPECT_FALSE(i == i2);

    ++i2;
    EXPECT_TRUE(i == i2);

    ++i;
    ++i2;
    EXPECT_TRUE(i == i2);

    ++i2;
    EXPECT_FALSE(i == i2);

    ++i;
    EXPECT_TRUE(i == i2);

    ++i;
    EXPECT_FALSE(i == i2);

    ++i2;
    EXPECT_TRUE(i == i2);
}

}  // testring
}  // libv

#endif  // LIBV_TESTS_BOOST_ITERATOR_ITERATOR_TESTS_H_